#include <stdio.h>
#include <config.h>
#include <asm/arch/cpm.h>
#include <asm/arch/clk.h>

#if 0
struct cgu {
	unsigned en:8;
	unsigned off:8;
	unsigned sel_bit:8;
	unsigned sel_src:8;
	unsigned char sel[4];
	unsigned ce:8;
	unsigned busy:8;
	unsigned stop:8;
	unsigned id:8;
};
struct cgu_clk_src {
	unsigned int cgu_clk;
	unsigned int src;
};
#endif
struct cgu cgu_clk_sel[CGU_CNT] = {
	[DDR] = {1, CPM_DDRCDR, 30, CONFIG_DDR_SEL_PLL, {0, APLL, MPLL, -1}, 29, 28, 27},
	[EL150] = {1, CPM_EL150CDR, 30, APLL, {APLL, MPLL, VPLL}, 29, 28, 27},
	[MACPHY] = {1, CPM_MACCDR, 30, APLL, {APLL, MPLL, VPLL}, 29, 28, 27},
	[LCD] = {1, CPM_LPCDR, 30, VPLL, {APLL, MPLL, VPLL}, 28, 27, 26},
	[MSC] = {1, CPM_MSC0CDR, 30, MPLL, {APLL, MPLL, EPLL, EXCLK}, 29, 28, 27},
	[MSC1] = {0, CPM_MSC1CDR, 0, 0, {-1, -1, -1, -1}, 29, 28, 27},
	[I2S] = {1, CPM_I2STCDR, 30, APLL, {APLL, MPLL, VPLL}, 29, 28, 27}, //需要再配置; i2s 使用VPLL
	[SFC] = {1, CPM_SFCCDR, 30, APLL, {APLL, MPLL, VPLL}, 29, 28, 27}, /* TODO */
	[CIM0] = {1, CPM_CIM0CDR, 30, APLL, {APLL, MPLL, VPLL, EPLL}, 29, 28, 27},
	[CIM1] = {1, CPM_CIM1CDR, 30, APLL, {APLL, MPLL, VPLL, EPLL}, 29, 28, 27},
	[CIM2] = {1, CPM_CIM2CDR, 30, APLL, {APLL, MPLL, VPLL, EPLL}, 29, 28, 27},
	[ISP] = {1, CPM_ISPCDR, 30, APLL, {APLL, MPLL, VPLL}, 29, 28, 27},
};

static void gen_cgu_params(struct clk_cgu_setting *cgusetting)
{
	/*stop clk and set div max*/
	int i, id;
	struct cgu *cgu = NULL;
	struct cgu_clk_src cgu_clk_src[] = CGU_CLK_SRC;
	unsigned regval = 0, reg = 0;

	for (i = 0; cgu_clk_src[i].cgu_clk != SRC_EOF; i++) {
		id = cgu_clk_src[i].cgu_clk;
		cgu_clk_sel[id].sel_src = cgu_clk_src[i].src;
	}

	for (id = 0; id < CGU_CNT; id++) {
		cgu = &(cgu_clk_sel[id]);
		reg = CPM_BASE + cgu->off;

		regval = 0;
		cgusetting[id].sel_val = 0;
		for (i = 0; i < 5; i++) {
			if (cgu->sel_src == cgu->sel[i]) {
				cgusetting[id].sel_val = i << cgu->sel_bit;
			}
		}
		if(cgu->busy) {
//			if(id == RSA) {
//				regval |= (0x2 | (1 << cgu->ce));
//			} else {
				/*set div max*/
				regval |= (0xfe | (1 << cgu->ce)/* | (1 << cgu->stop)*/);
//			}
		} else {
			/*clear ce*/
			regval &= ~(1 << cgu->ce);
		}

		cgusetting[id].addr = reg;
		cgusetting[id].val = regval;
		cgusetting[id].sel_src = cgu_clk_sel[id].sel_src;
		cgusetting[id].ce = cgu->ce;
		cgusetting[id].busy = cgu->busy;
		cgusetting[id].stop = cgu->stop;
	}
}

static void file_head_print(void)
{
	printf("/*\n");
	printf(" * DO NOT MODIFY.\n");
	printf(" *\n");
	printf(" * This file was generated by clk_params_creator\n");
	printf(" *\n");
	printf(" */\n");
	printf("\n");

	printf("#ifndef __CLK_REG_VALUES_H__\n");
	printf("#define __CLK_REG_VALUES_H__\n\n");
}

static void file_end_print(void)
{
	printf("\n#endif /* __CLK_REG_VALUES_H__ */\n");
}

int main(int argc, char *argv[])
{
	struct clk_cgu_setting cgusetting[CGU_CNT];
	int i;

	gen_cgu_params(cgusetting);
	file_head_print();
	printf("#define CGU_REG_VALUE  {\\\n");
	for (i = 0; i < CGU_CNT; i++) {
		printf("\t{0x%08x, 0x%08x, %d, %d, %d, %d, 0x%08x}, \\\n",
		       cgusetting[i].addr, cgusetting[i].val,		\
		       cgusetting[i].ce, cgusetting[i].busy, cgusetting[i].stop, \
		       cgusetting[i].sel_src, cgusetting[i].sel_val);
	}
	printf("\t}\n");
	file_end_print();
	return 0;
}
